﻿Imports System.Data
Imports Kairyu.Load
Imports Kairyu.Connection

Namespace Save
    ''' <summary>
    ''' モデル保存クラス
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ModelSaver
        Inherits ModelLoader

        Public Sub New(ByVal trn As IDbTransaction, ByVal prefix As String)
            MyBase.New(trn, prefix)
        End Sub

#Region "拡張機能"
        ''' <summary>
        ''' 保存が実行される前に行う処理を示します
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>IDの自動採番などに利用してください</remarks>
        Public Shared Property OnPreviousSave As Action(Of ModelSaver, SaveDefinition) = AddressOf (New KeyWriter).SetKeyOnPreviousSave

        ''' <summary>
        ''' 保存が実行された値に行う処理を示します
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>SQLサーバーのオートナンバーセット、ストアドの実行などに利用してください</remarks>
        Public Shared Property OnAfterSave As Action(Of ModelSaver, SaveDefinition) = AddressOf (New KeyWriter).SetKeyOnAfterSave
#End Region

#Region "Save メソッド"

        Private Property CommandInfoLevel As InfoLevelEnum = InfoLevelEnum.Info

        Public Sub Save(model As Object, strage As Storage)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = strage.CreateSaveDefinitions(model)
            Me.Save(defs)
        End Sub

        Public Sub Save(models As ICollection, strage As Storage)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = strage.CreateSaveDefinitions(models)
            Me.Save(defs)
        End Sub
#End Region

#Region "SaveAsNew メソッド"
        Public Sub SaveAsNew(model As Object)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = (New Storage).CreateSaveDefinitions(model, SaveType.Create)
            Me.Save(defs)
        End Sub

        Public Sub SaveAsNew(models As ICollection)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = (New Storage).CreateSaveDefinitions(models, SaveType.Create)
            Me.Save(defs)
        End Sub
#End Region

#Region "SaveAsDelete メソッド"
        Public Sub SaveAsDelete(model As Object)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = (New Storage).CreateSaveDefinitions(model, SaveType.Delete)
            Me.Save(defs)
        End Sub

        Public Sub SaveAsDelete(models As ICollection)
            '保存定義を作成
            Dim defs As List(Of SaveDefinition) = (New Storage).CreateSaveDefinitions(models, SaveType.Delete)
            Me.Save(defs)
        End Sub
#End Region

        Public Sub Save(def As SaveDefinition)
            Dim lst As New List(Of SaveDefinition)
            lst.Add(def)
            Me.Save(lst)
        End Sub

        ''' <summary>
        ''' 保存定義書をもとに保存します
        ''' </summary>
        ''' <param name="defs"></param>
        ''' <remarks></remarks>
        Public Sub Save(defs As List(Of SaveDefinition))
            Dim sw As New Stopwatch
            sw.Start()

            Dim rows As Integer = 0
            For Each def As SaveDefinition In defs
                '事前処理
                If OnPreviousSave IsNot Nothing Then OnPreviousSave.Invoke(Me, def)

                '保存処理
                Dim saveCommand As IDbCommand = SaveCommandFactory.Create(def, Me.Transaction, Me.ParameterPrefix)

                '保存処理判定
                Dim cnt As Integer = saveCommand.ExecuteNonQueryWithLog(def.TableAttribute.TableName)
                rows += cnt
                If cnt = 0 Then
                    Throw New ConflictException(def.Model)
                ElseIf cnt <> 1 Then
                    '#67　トリガを使うとORMが失敗するときがある
                    '更新件数が1以外の場合、必ずしも以上とは言えないので、通知します
                    '何も指定しない場合、ManySaveExceptionが発生しますので、必要に応じにて同関数を差し替えしてください
                    Log.OnOneModelManySave.Invoke(def.Model, New ManySaveEventArgs(def.TableAttribute.TableName, saveCommand, cnt))
                End If

                '事後処理
                If OnAfterSave IsNot Nothing Then OnAfterSave.Invoke(Me, def)
            Next

            sw.Stop()
            Log.DoFinishAction(Me, New FinishEventArgs(sw.ElapsedMilliseconds, rows))
        End Sub

    End Class

End Namespace
